/* Copyright 2010 Unicomp Kft. All rights reserved. Released under BSD license below.


Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice, this list of
      conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above copyright notice, this list
      of conditions and the following disclaimer in the documentation and/or other materials
      provided with the distribution.

THIS SOFTWARE IS PROVIDED BY UNICOMP KFT AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of Unicomp Kft.
*/


/*
 * @author Gabor Salamon <gabor.salamon@unicomp.hu>
 */

#include "Sht21.h"

module Sht21LogicP
{
	provides interface Sht21Logic;
	uses interface I2CPacket<TI2CBasicAddr> as I2CPacket;
	uses interface Resource as I2CResource;
	uses interface GeneralIO as Power;
	uses interface Timer<TMilli>;
	
	//uses interface Leds;
}
implementation
{
	norace uint8_t state;
	norace error_t err;
	uint8_t txBuf[4];
	uint8_t rxBuf[4];
	uint8_t regData;
	norace uint8_t *pRegData = NULL;
	norace uint16_t *pData = NULL;
	
	void I2CWrite(uint8_t *data, uint8_t len);
	void I2CRead(uint8_t *data, uint8_t len);
	
	task void SignalDone();
	
	command void Sht21Logic.PowerOff()
	{
		state = SHT_STATE_OFF;
		call Power.clr();
		call Power.makeInput();
	}

	command void Sht21Logic.PowerOn()
	{
		state = SHT_STATE_ON_IDLE;
		call Power.makeOutput();
		call Power.set();
	}
	
	command error_t Sht21Logic.Reset()
	{
		if(state == SHT_STATE_ON_IDLE)
		{
			state = SHT_STATE_RESET;
			return call I2CResource.request();
		}
		else return FAIL;
	}

	command error_t Sht21Logic.SetRegister(uint8_t *data)
	{
		if(state == SHT_STATE_ON_IDLE)
		{
			state = SHT_STATE_SET_REG;
			regData = *(data);
			return call I2CResource.request();
		}
		else return FAIL;
	}
	
	command error_t Sht21Logic.GetRegister(uint8_t *data)
	{
		if(state == SHT_STATE_ON_IDLE)
		{
			state = SHT_STATE_GET_REG;
			pRegData = data;
			return call I2CResource.request();
		}
		else return FAIL;
	}

	command error_t Sht21Logic.GetHumid(uint16_t *data)
	{
		if(state == SHT_STATE_ON_IDLE)
		{
			state = SHT_STATE_GET_HUMID;
			pData = data;
			return call I2CResource.request();
		}
		else return FAIL;
	}
	
	command error_t Sht21Logic.GetTemp(uint16_t *data)
	{
		
		if(state == SHT_STATE_ON_IDLE)
		{
			state = SHT_STATE_GET_TEMP;
			pData = data;
			return call I2CResource.request();
		}
		else return FAIL;
	}

	event void I2CResource.granted()
	{
		switch(state)
		{
			case SHT_STATE_RESET:
			{
				txBuf[0] = SHT_RESET;
				I2CWrite(&txBuf[0], 1);
				break;
			}
			case SHT_STATE_SET_REG:
			{
				txBuf[0] = SHT_W_REG;
				txBuf[1] = regData;
				I2CWrite(&txBuf[0], 2);
				break;
			}
			case SHT_STATE_GET_REG:
			{
				txBuf[0] = SHT_R_REG;
				I2CWrite(&txBuf[0], 1);
				break;
			}
			case SHT_STATE_GET_HUMID:
			{
				txBuf[0] = SHT_HUMID;
				I2CWrite(&txBuf[0], 1);
				break;
			}
			case SHT_STATE_GET_TEMP:
			{
				txBuf[0] = SHT_TEMP;
				I2CWrite(&txBuf[0], 1);
				break;
			}
			
		}
	}

	async event void I2CPacket.writeDone(error_t error, uint16_t addr, uint8_t length, uint8_t *data)
	{
		err = error;
		if(error == SUCCESS)
		{
			switch(state)
			{
				case SHT_STATE_RESET:
				{
					post SignalDone();
					//state = SHT_STATE_ON_IDLE;
					//call I2CResource.release();
				}
				case SHT_STATE_SET_REG:
				{
					post SignalDone();
					//state = SHT_STATE_ON_IDLE;
					//signal Sht21Logic.SetRegisterDone(error, pRegData);
					//pRegData = NULL;
					//pData = NULL;
					//call I2CResource.release();
					break;
				}
				case SHT_STATE_GET_REG:
				{
					//I2CRead(&rxBuf[0], 1);
					call Timer.startOneShot(SHT_WAIT);
					break;
				}
				case SHT_STATE_GET_HUMID:
				{
					//I2CRead(&rxBuf[0], 3);
					call Timer.startOneShot(SHT_WAIT);
					break;
				}
				case SHT_STATE_GET_TEMP:
				{
					//I2CRead(&rxBuf[0], 3);
					call Timer.startOneShot(SHT_WAIT);
					break;
				}
			}
		}
		else 
		{
			post SignalDone();
		}
	}
	
	event void Timer.fired()
	{
		switch(state)
		{
			case SHT_STATE_GET_REG:
			{
				I2CRead(&rxBuf[0], 1);
				break;
			}
			case SHT_STATE_GET_HUMID:
			{
				I2CRead(&rxBuf[0], 3);
				break;
			}
			case SHT_STATE_GET_TEMP:
			{
				I2CRead(&rxBuf[0], 3);
				break;
			}
		}
	}
	
	async event void I2CPacket.readDone(error_t error, uint16_t addr, uint8_t length, uint8_t *data)
	{
		err = error;
		if(error == SUCCESS)
		{
			switch(state)
			{
				case SHT_STATE_GET_REG:
				{
					*(pRegData) = *(data);
					//signal Sht21Logic.GetRegisterDone(error, pRegData);
					//pRegData = NULL;
					//pData = NULL;
					break;
				}
				case SHT_STATE_GET_HUMID:
				{
					*pData = (uint16_t)(*data << 8 | *(data + 1));
					//signal Sht21Logic.GetHumidDone(error, pData);
					//pRegData = NULL;
					//pData = NULL;
					break;
				}
				case SHT_STATE_GET_TEMP:
				{
					*pData = (uint16_t)(*data << 8 | *(data + 1));
					//signal Sht21Logic.GetTempDone(error, pData);
					//pRegData = NULL;
					//pData = NULL;
					break;
				}
			}
		}
		
		post SignalDone();
	}
	
	void I2CWrite(uint8_t *data, uint8_t len)
	{
		if(call I2CPacket.write(I2C_START | I2C_STOP, SHT_ADDRESS, len, data) != SUCCESS) 
		{
			post SignalDone();
		}
	}
	
	void I2CRead(uint8_t *data, uint8_t len)
	{
		if(call I2CPacket.read(I2C_START | I2C_STOP, SHT_ADDRESS, len, data) != SUCCESS) post SignalDone();
	}
	
	task void SignalDone()
	{
		call I2CResource.release();
		
		
		switch(state)
		{
			case SHT_STATE_RESET:
			{
				signal Sht21Logic.ResetDone(err);
			}
			case SHT_STATE_SET_REG:
			{
				signal Sht21Logic.SetRegisterDone(err, pRegData);
				break;
			}
			case SHT_STATE_GET_REG:
			{
				signal Sht21Logic.GetRegisterDone(err, pRegData);
				break;
			}
			case SHT_STATE_GET_HUMID:
			{
				signal Sht21Logic.GetHumidDone(err, pData);
				break;
			}
			case SHT_STATE_GET_TEMP:
			{
				signal Sht21Logic.GetTempDone(err, pData);
				break;
			}
		}
		
		state = SHT_STATE_ON_IDLE;
		pRegData = NULL;
		pData = NULL;
	}

}
